/* Copyright   1991 Gustavus Adolphus College.  All rights reserved.
 *
 * Schematik was developed by Gustavus Adolphus College (GAC) with
 * support from NeXT Computer, Inc.  Permission to copy this software,
 * to redistribute it, and to use it for any purpose is granted,
 * subject to the following restrictions and understandings.
 *
 * 1. Any copy made of this software must include this copyright
 * notice in full.
 *
 * 2. Users of this software agree to make their best efforts (a) to
 * return to the GAC Mathematics and Computer Science Department any
 * improvements or extensions that they make, so that these may be
 * included in future releases; and (b) to inform GAC of noteworthy
 * uses of this software.
 *
 * 3. All materials developed as a consequence of the use of this
 * software shall duly acknowledge such use, in accordance with the
 * usual standards of acknowledging credit in academic research.
 *
 * 4. GAC makes no express or implied warranty or representation of
 * any kind with respect to this software, including any warranty
 * that the operation of this software will be error-free.  ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
 * PURPOSE IS HEREBY DISCLAIMED.  GAC is under no obligation to
 * provide any services, by way of maintenance, update, or otherwise.
 *
 * 5. In conjunction with products arising from the use of this
 * material, there shall be no use of the name of Gustavus Adolphus
 * College nor of any adaptation thereof in any advertising,
 * promotional, or sales literature without prior written consent
 * from GAC in each case.
 */

#import "HelpAgent.h"
#import "../defines.h"
#import Main_h
#import PrefAgent_h
#import <appkit/NXBrowser.h>
#import <appkit/NXBrowserCell.h>
#import <appkit/ScrollView.h>
#import <appkit/Text.h>
#import <sys/dir.h>
#import <fcntl.h>
#import <libc.h>
#import <mach.h>
#import <string.h>

#define NIBFILE1		"Help.nib"
#define NIBFILE2		"Manual.nib"
#define HELPZONENAME		"HelpAgnt"
#define MINHELPWINDOWHEIGHT	95
#define MINHELPWINDOWWIDTH	400
#define MINMANWINDOWHEIGHT	130
#define MINMANWINDOWWIDTH	550

#define MANUALPANELTITLE	LocalString("Scheme 7.1 Reference Manual",NULL)
#define MANUALBROWSERTITLE	LocalString("Page",NULL)
#define ENTRYFORMTITLE		LocalString("Search for Entry:",NULL)
#define SEARCHBUTTONTITLE	LocalString("Search",NULL)

static char **addFile(const char *, char **, int);
static int compare(void *, void *);

static NXZone *helpZone=NULL;
static char **topics=NULL;
static id theAgent=nil;

@implementation HelpAgent

+ new
{
DEBUG_FUNC1(DEBUGLEVEL);
    if (theAgent==nil)
      {
        NXZone *tempZone;

        tempZone = NXCreateZone(vm_page_size, vm_page_size, YES);
        DEBUG_ASSERT(tempZone!=NULL)
        theAgent = self = [super allocFromZone:tempZone];
	helpZone = agentZone = tempZone;
	NXNameZone(agentZone, HELPZONENAME);
      }
    return theAgent;
}

- activateAgent:sender
{
DEBUG_FUNC1(DEBUGLEVEL);
    switch ([sender tag])
      {
        case MENU_INFO_Help  : if (!helpPanel)
				 {
				   helpPanel = LoadNIB(NIBFILE1, theAgent, agentZone);
				   DEBUG_ASSERT(helpPanel!=nil)
				   [helpPanel useOptimizedDrawing:YES];
				   [helpPanel setTitle:HELPPANELTITLE];
				   [topicsBrowser setTitle:HELPBROWSERTITLE ofColumn:BROWSERCOLUMN];
				   [topicsBrowser loadColumnZero];
				   DEBUG_ASSERT([topicsBrowser isLoaded])
				 }
			       [helpPanel makeKeyAndOrderFront:self];
			       break;
        case MENU_INFO_Manual: if (!manualPanel)
				 {
				   manualPanel = LoadNIB(NIBFILE2, theAgent, agentZone);
				   DEBUG_ASSERT(manualPanel!=nil)
				   [manualPanel useOptimizedDrawing:YES];
#if 0
				   [manualPanel setTitle:MANUALPANELTITLE];
				   [pageBrowser setTitle:MANUALBROWSERTITLE ofColumn:BROWSERCOLUMN];
				   [pageBrowser setDoubleAction:@selector(manualBrowserDoubleClick:)];
				   [entryField setTitle:ENTRYFORMTITLE at:0];
				   [[entryField target] setTitle:SEARCHBUTTONTITLE];
				   [pageBrowser loadColumnZero];
				   DEBUG_ASSERT([pageBrowser isLoaded])
#endif
				 }
			       [manualPanel makeKeyAndOrderFront:self];
      }
    return self;
}

- helpBrowserClick:sender
{
    extern char *appDirectory;
    const char *topic=[[[sender matrixInColumn:BROWSERCOLUMN] selectedCell] stringValue];

DEBUG_FUNC1(DEBUGLEVEL);
    if ((topic!=NULL)&&(*topic))
      {
        NXStream *stream;
        char helpFile[strlen(appDirectory)+strlen(topic)+strlen(FILENAMETEMPLATE)+strlen(NOHELPFILE)];

        sprintf(helpFile, FILENAMETEMPLATE, appDirectory, topic);
        if (!(stream = NXMapFile(helpFile, NX_READONLY)))
          {
            sprintf(helpFile, FILENAMETEMPLATE, appDirectory, NOHELPFILE);
            stream = NXMapFile(helpFile, NX_READONLY);
          }
        if (stream)
          {
            [helpPanel disableFlushWindow];
            [[helpScrollView docView] readRichText:stream];
	    [[helpScrollView docView] scrollSelToVisible];
            [[helpPanel reenableFlushWindow] flushWindow];
            NXCloseMemory(stream, NX_FREEBUFFER);
          }
      }
    return self;
}

#if 0
- manualBrowserClick:sender
{
    return self;
}

- manualBrowserDoubleClick:sender;
{
    const char *label=[[[sender matrixInColumn:BROWSERCOLUMN] selectedCell] stringValue];
    return self;
}
#endif

- (id)helpScrollView	{ return helpScrollView;}

@end

@implementation HelpAgent (HelpBrowserDelegate)

- (int)browser:sender fillMatrix:matrix inColumn:(int)column
{
    extern char *appDirectory;
    char helpDirectory[strlen(appDirectory)+strlen(HELPDIR)];
    int fd,count=0;
    char **list=NULL;

DEBUG_FUNC1(DEBUGLEVEL);
    sprintf(helpDirectory, HELPDIR, appDirectory);
    if ((fd = open(helpDirectory, O_RDONLY, 0644))>0)
      {
        long basep;
        char dirbuf[vm_page_size],*buf;
        struct direct *dp;
        int cc=getdirentries(fd, (buf = dirbuf), vm_page_size, &basep);

        while (cc)
          {
            dp = (struct direct *)buf;
            if ((dp->d_name[0])&&(dp->d_name[0]!='.'))
              list = addFile(dp->d_name, list, count++);
            buf += dp->d_reclen;
            if (buf>=dirbuf+cc)
              cc = getdirentries(fd, (buf = dirbuf), vm_page_size, &basep);
          }
        close(fd);
        if (list)
          qsort(list, count, sizeof(char *), compare);
      }
    if (topics)
      {
        int i;
        for(i=0; topics[i]; i++)
          NXZoneFree(agentZone, topics[i]);
        NXZoneFree(agentZone, topics);
      }
    topics = list;
    return count;
}

- browser:sender loadCell:aCell atRow:(int)row inColumn:(int)column
{
DEBUG_FUNC1(DEBUGLEVEL);
    if (topics)
      {
        [aCell setStringValueNoCopy:topics[row]];
        DEBUG_ASSERT(!NXOrderStrings((unsigned char *)[aCell stringValue], (unsigned char *)topics[row], YES, -1, NULL))
        [aCell setLeaf:YES];
        [aCell setLoaded:YES];
      }
    return self;
}

@end

@implementation HelpAgent (Delegate)

- windowWillResize:sender toSize:(NXSize *)frameSize
{
DEBUG_FUNC1(DEBUGLEVEL);
    if ([sender isEqual:helpPanel])
      {
	if (frameSize->width<MINHELPWINDOWWIDTH)
	  frameSize->width = MINHELPWINDOWWIDTH;
	if (frameSize->height<MINHELPWINDOWHEIGHT)
	  frameSize->height = MINHELPWINDOWHEIGHT;
      }
    else if ([sender isEqual:manualPanel])
      {
	if (frameSize->width<MINMANWINDOWWIDTH)
	  frameSize->width = MINMANWINDOWWIDTH;
	if (frameSize->height<MINMANWINDOWHEIGHT)
	  frameSize->height = MINMANWINDOWHEIGHT;
      }
    return self;
}

- windowWillClose:sender
{
DEBUG_FUNC1(DEBUGLEVEL);
    if ([sender isEqual:helpPanel])
      helpPanel = nil;
    else if ([sender isEqual:manualPanel])
      manualPanel = nil;
    return self;
}

@end

#define CHUNK	3

static char **addFile(const char *file, char **list, int count)
{
    char *suffix;

    if (!list)
      list = (char **)NXZoneMalloc(helpZone, CHUNK*sizeof(char *));
    DEBUG_ASSERT(list!=NULL)
    if (suffix = rindex(file, '.'))
      *suffix = '\0';
    list[count] = NXCopyStringBufferFromZone(file, helpZone);
    DEBUG_ASSERT(list[count]!=NULL)
    count++;
    if (!(count%CHUNK))
      list = (char **)NXZoneRealloc(helpZone, list, (count+CHUNK)*sizeof(char *));
    DEBUG_ASSERT(list!=NULL)
    list[count] = NULL;
    return list;
}

static int compare(void *arg1, void *arg2)
{
    return NXOrderStrings(*((unsigned char **)arg1), *((unsigned char **)arg2), NO, -1, NULL);
}

@implementation ManualView

- initFrame:(NXRect *)aRect
{
    return self;
}

- drawSelf:(const NXRect *)rects :(int)rectCount
{
    return self;
}

- displayPage:(unsigned)aPage at:(int)aLocation
{
    return self;
}

- generateIndex
{
    return self;
}

@end

@implementation ManualView (PageBrowserDelegate)
#if 0
- (int)browser:sender fillMatrix:matrix inColumn:(int)column
{
    int count;
    id aCell;

DEBUG_FUNC1(DEBUGLEVEL);
    for(count=0; count<[entryIndexList count]; count++)
      {
        [matrix addRow];
	aCell = [matrix cellAt:count :0];
	[aCell setStringValue:[[entryIndexList objectAt:count] entry]];
	[aCell setLeaf:YES];
	[aCell setLoaded:YES];
      }
    return count+1;
}
#endif
@end

@implementation ManualEntry

- init:(char *)anEntry page:(short)aPage line:(int)aLine label:(char *)aLabel x:(short)x y:(short)y
{
    [super init];
    entryName = NXCopyStringBuffer(anEntry);
    absPage = aPage;
    pageStartLine = aLine;
    pageLabel = NXCopyStringBuffer(aLabel);
    xPos = x;
    yPos = y;
    return self;
}

- (char *)entry		{ return entryName;}
- (char *)pageLabel;	{ return pageLabel;}
- (short)absolutePage;	{ return absPage;}
- (int)pageStartLine	{ return pageStartLine;}
- (short)xPosition;	{ return xPos;}
- (short)yPosition;	{ return yPos;}

@end
